package com.brainhealth.customer.service.impl;


import com.alibaba.fastjson.JSONObject;
import com.brainhealth.common.constant.CacheConstants;
import com.brainhealth.common.constant.Constants;
import com.brainhealth.common.constant.NumberConstants;
import com.brainhealth.common.core.redis.RedisCache;
import com.brainhealth.common.enums.AIRoleEnum;
import com.brainhealth.common.enums.ErnieBotEntranceEnum;
import com.brainhealth.common.enums.TokenTypeEnum;
import com.brainhealth.common.enums.YNEnum;
import com.brainhealth.common.utils.DateUtils;
import com.brainhealth.common.utils.NumberUtils;
import com.brainhealth.common.utils.StringUtils;
import com.brainhealth.customer.domain.ChatAiRecord;
import com.brainhealth.customer.domain.ChatAiTokens;
import com.brainhealth.customer.domain.ChatBase;
import com.brainhealth.customer.domain.params.ChatAiParam;
import com.brainhealth.customer.domain.vo.ChatAiContentVO;
import com.brainhealth.customer.domain.vo.ChatAiVO;
import com.brainhealth.customer.service.*;
import io.jsonwebtoken.lang.Assert;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.brainhealth.common.constant.NumberConstants.TWO_THOUSAND;

@Service
public class AIChatServiceImpl implements IAIChatService {

    /**
     * 日志
     */
    Logger logger = LoggerFactory.getLogger(this.getClass());

    public static final String CHAT_PROMPT="prompt";


    @Autowired
    IChatService chatService;

    @Autowired
    IChatAiTokensService chatAiTokensService;

    @Autowired
    IChatAiRecordService chatAiRecordService;

    @Autowired
    IErnieBotService ernieBotService;

    @Autowired
    private RedisCache redisCache;

    @Override
    public String getAccessToken(){
        Object cacheObject = redisCache.getCacheObject(CacheConstants.TOKENS_ERNIE_BOT);
        if (null==cacheObject || StringUtils.isBlank(String.valueOf(cacheObject))) {
            String accessToken = ernieBotService.getAccessToken();
            if (StringUtils.isBlank(accessToken)) {
                return null;
            }else{
                redisCache.setCacheObject(CacheConstants.TOKENS_ERNIE_BOT,accessToken);
                cacheObject= redisCache.getCacheObject(CacheConstants.TOKENS_ERNIE_BOT);
            }
        }
        String accessToken = String.valueOf(cacheObject);
        return accessToken;
    }

    @Override
    public ChatAiContentVO getChatAiContent(HttpServletRequest request, ChatAiParam chatAiParam) {
        long ts = DateUtils.getTimeMillis();
        try {
            logger.info("ts:{}，获取文心一言对话，入参:{}", ts, chatAiParam);
            checkParam(chatAiParam);
            ChatBase chatBase = chatService.getChatBase(request);
            //校验用户使用<文心一言>聊天字数，不能超过2000
            ChatAiVO chatAiVO = getChatAiVO(chatBase);
            Long totalTokens = chatAiVO.getTotalTokens();
            if (null!=totalTokens && totalTokens> TWO_THOUSAND){
                logger.warn("用户{}订单{}课程{}聊天字数{}超过{}阈值",chatBase.getCustomerId(),chatBase.getOrderNo(),chatBase.getCourseNo(),totalTokens,TWO_THOUSAND);
                throw new Exception("该课程使用tokens已达到上限");
            }
            String accessToken = getAccessToken();
            //获取文心一言问题答案
             JSONObject object= ernieBotService.getCompletion(accessToken,chatAiParam.getPrompt());
            //保存聊天内容
            Runnable task = new Runnable() {
                @Override
                public void run() {
                    saveChatAiRecord(chatBase, chatAiParam, object);
                }
            };
            Thread thread = new Thread(task, "thread-save-chat-ai-record");
            thread.start();
            //返回结果
            ChatAiContentVO chatErnieBotVO = new ChatAiContentVO();
            String result = ernieBotService.getErnieBotResult(object);
            chatErnieBotVO.setChatContent(result);
            //chatAiVO = getChatAiVO(chatBase);
            Long currentTokens = ernieBotService.getTotalTokens(object, TokenTypeEnum.TOTAL_TOKENS);
            currentTokens = null == currentTokens ? 0 : currentTokens;
            totalTokens =  null==totalTokens?0:totalTokens;
            totalTokens = totalTokens+currentTokens;
            chatErnieBotVO.setTotalTokens(totalTokens);
            return chatErnieBotVO;
        } catch (Exception e) {
            logger.info("ts:{}，获取文心一言对话，异常", ts, e);
            return null;
        }
    }

    void checkParam(ChatAiParam chatAiParam) {
        Assert.state(null != chatAiParam.getChatEntrance(), "文心一言入口不能为空");
        Assert.state(ErnieBotEntranceEnum.isValidateErnieBotCode(chatAiParam.getChatEntrance().intValue()), "文心一言入口值不正确");
        Assert.state(StringUtils.isNotBlank(chatAiParam.getPrompt()), "问题不能为空");
        Assert.state(chatAiParam.getPrompt().length() <= TWO_THOUSAND, "问题字数不能超过2400字");
    }

    ChatAiVO getChatAiVO(ChatBase chatBase) {
        ChatAiTokens chatAiTokens = new ChatAiTokens();
        BeanUtils.copyProperties(chatBase, chatAiTokens);
        ChatAiVO chatAiVO = getChatAiVO(chatAiTokens);
        return chatAiVO;
    }

    @Transactional
    public Integer saveChatAiRecord(ChatBase chatBase,ChatAiParam chatAiParam,JSONObject jsonObject) {
        long ts = DateUtils.getTimeMillis();
        try {
            logger.info("ts:{} ，保存文心一言聊天记录，入参{}，结果{}", ts, chatAiParam,jsonObject);

            Long customerId = chatBase.getCustomerId();
            Date now = DateUtils.getNowDate();
            String strCustomerId = null == customerId ? "" : String.valueOf(customerId);
            String orderNo = chatBase.getOrderNo();
            Long countSort = chatBase.getCourseNo();
            ChatAiTokens chatAiTokens = new ChatAiTokens();
            BeanUtils.copyProperties( chatBase,chatAiTokens);
            chatAiTokens.setChatEntrance(chatAiParam.getChatEntrance());
            List<ChatAiTokens> chatErnieBotRecordList = chatAiTokensService.selectChatAiTokensList(chatAiTokens);
            if (CollectionUtils.isNotEmpty(chatErnieBotRecordList)) {
                ChatAiTokens chatAiToken = chatErnieBotRecordList.get(0);
                Long chatTotalTokens = chatAiToken.getTotalTokens();
                chatTotalTokens = chatTotalTokens + ernieBotService.getTotalTokens(jsonObject, TokenTypeEnum.TOTAL_TOKENS);
                chatAiToken.setTotalTokens(chatTotalTokens);
                chatAiToken.setUpdateUser(strCustomerId);
                chatAiToken.setUpdateTime(now);
                int updateResult = chatAiTokensService.updateChatAiTokens(chatAiToken);
                logger.info("ts:{} ，更新文心一言聊天字数(tokens)，结果:{}", ts, updateResult);
            }else{
                chatAiTokens = new ChatAiTokens();
                chatAiTokens.setCustomerId(customerId);
                chatAiTokens.setOrderNo(orderNo);
                chatAiTokens.setCourseNo(countSort);
                chatAiTokens.setChatEntrance(chatAiParam.getChatEntrance());
                chatAiTokens.setTotalTokens(ernieBotService.getTotalTokens(jsonObject, TokenTypeEnum.TOTAL_TOKENS));
                chatAiTokens.setYn(YNEnum.NO.getCode());
                chatAiTokens.setCreateUser(strCustomerId);
                chatAiTokens.setCreateTime(now);
                int insertResult = chatAiTokensService.insertChatAiTokens(chatAiTokens);
                logger.info("ts:{} ，新增文心一言聊天字数，结果:{}", ts, insertResult);
            }

            ChatAiRecord promptChatAiRecord = constructChatAiRecord(chatBase,chatAiParam,jsonObject,AIRoleEnum.PROMPT);
            ChatAiRecord completionChatAiRecord = constructChatAiRecord(chatBase,chatAiParam,jsonObject,AIRoleEnum.COMPLETION);
            List<ChatAiRecord> chatAiRecordList = new ArrayList<>();
            chatAiRecordList.add(promptChatAiRecord);
            chatAiRecordList.add(completionChatAiRecord);
            int insertRecordResult = chatAiRecordService.batchInsertChatAiRecord(chatAiRecordList);
            logger.info("ts:{} ，新增文心一言聊天记录，结果:{}", ts, insertRecordResult);
            return insertRecordResult;
        } catch (Exception e) {
            logger.info("ts:{} ，新增文心一言聊天记录，异常", ts, e);
            return null;
        }
    }

    private ChatAiRecord constructChatAiRecord(ChatBase chatBase,ChatAiParam chatAiParam, JSONObject object, AIRoleEnum role)
    {
        if (null==object){
            return null;
        }

        String chatContent;
        Long tokens ;
        if (AIRoleEnum.PROMPT.equals(role)) {
            chatContent = chatAiParam.getPrompt();
            //问题tokens数
            Object usage = object.get("usage");
            Map map = (Map) usage;
            Object promptTokens = map.get("prompt_tokens");
            tokens = NumberUtils.toLong(promptTokens);
        } else {
            Object result = object.get("result");
            chatContent = String.valueOf(result);
            //答案tokens数
            Object usage = object.get("usage");
            Map map = (Map) usage;
            Object promptTokens = map.get("completion_tokens");
            tokens = NumberUtils.toLong(promptTokens);
        }

        ChatAiRecord chatAiRecord=new ChatAiRecord();
        BeanUtils.copyProperties(chatBase,chatAiRecord);
        Integer recordId = getRecordId(chatAiRecord);
        chatAiRecord.setRecordId(recordId);
        chatAiRecord.setChatEntrance(chatAiParam.getChatEntrance());
        chatAiRecord.setRole(role.getCode());
        chatAiRecord.setChatContent(chatContent);
        chatAiRecord.setTokens(tokens);

        chatAiRecord.setYn(YNEnum.NO.getCode());
        Long customerId = chatBase.getCustomerId();
        String strCustomerId = null == customerId ? "" : String.valueOf(customerId);
        chatAiRecord.setCreateUser(strCustomerId);
        Date now = DateUtils.getNowDate();
        chatAiRecord.setCreateTime(now);
        chatAiRecord.setUpdateUser(strCustomerId);
        chatAiRecord.setUpdateTime(now);

        return chatAiRecord;
    }

    private Integer getRecordId(ChatAiRecord chatAiRecord)
    {
        Integer maxRecordId = chatAiRecordService.getMaxRecordId(chatAiRecord);
        if(null==maxRecordId){
            maxRecordId= NumberConstants.ZERO;
        }
        Integer recordId=maxRecordId+1;
        return recordId;
    }

    @Override
    public ChatAiVO getChatAiVO(ChatAiTokens chatAiTokens) {
        long ts = DateUtils.getTimeMillis();
        try {
            logger.info("ts:{} ，获取文心一言聊天统计结果，入参{}", ts, chatAiTokens);
            ChatAiVO chatErnieBotVO = chatAiTokensService.getChatAiVO(chatAiTokens);
            logger.info("ts:{} ，获取文心一言聊天统计结果，结果{}", ts, chatErnieBotVO);
            return chatErnieBotVO;
        }catch (Exception e){
            logger.info("ts:{} ，获取文心一言聊天统计结果，异常", ts, e);
            return null;
        }

    }

}
